﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Daybreak.Core.Terrains
{
    public abstract class HeightData
    {
        /// <summary>
        /// The height of the terrain specified by the heightmap file 
        /// </summary>
        public abstract int Height {get; }

        /// <summary>
        /// The width of the terrain specified by the heightmap file 
        /// </summary>
        public abstract int Width { get; }

        public abstract bool Loaded { get; }

        public abstract Array2D DataArray {get; }
    }

    /// <summary>
    /// Raw data format for height maps 
    /// </summary>
    public class RawHeightData : HeightData
    {
        private int _bpp;
        private int _height;
        private int _width;
        private Array2D _array;

        /// <summary>
        /// Default ctor
        /// </summary>
        /// <param name="rawDataFile"></param>
        public RawHeightData(string rawDataFile)
        {
            if (string.IsNullOrEmpty(rawDataFile))
                return;

            if (rawDataFile.EndsWith("1"))
                _bpp = 1;

            if (rawDataFile.EndsWith("2"))
                _bpp = 2;

            Load(rawDataFile);

        }

        private void Load(string rawDataFile)
        {
            int len;

            byte[] buffer;

            try
            {
                // binary load
                using (FileStream fs = new FileStream(rawDataFile, FileMode.Open))
                {

                    // width and height are, for now, considered the same (i.e. 512x512, 1024x1024, etc)
                    // as those are the most common raw heightmap file dimensions
                    _width = (int)Math.Sqrt((double)fs.Length / _bpp);
                    _height = Width;

                    // the offset has the dimensions width x height x bits per pixel
                    len = _width * _height * _bpp;
                    buffer = new byte[len];

                    // read the data from the file and store it into the byte array
                    fs.Read(buffer, 0, len);
                }
            }
            catch
            {
                buffer = null;
                _bpp = 0;
            }

            if (buffer != null)
            {
                _array = new Array2D(_width, _height);

                int offset = 0;

                for (int i = 0; i < _array.Array.Length; i++)
                {
                    _array.Array[i] = GetHeight(buffer, offset);

                    offset += _bpp;
                }
            }
        }

        private float GetHeight(byte[] buffer, int offset)
        {
            int yVertex = 0;

            switch (_bpp)
            {
                case 1:
                    yVertex = (buffer[offset]);
                    break;
                case 2:
                    yVertex = (buffer[offset]) + ((buffer[offset + 1]) << 8);
                    break;
                default:
                    yVertex = 0;
                    break;
            }

            return (yVertex * (255.0f / (1 << 16)));

        }

        public override bool Loaded
        {
            get { return _bpp > 0; }
        }

        public override int Height
        {
            get { return _height; }
        }

        public override int Width
        {
            get { return _width; }
        }

        public override Array2D DataArray
        {
            get { return _array; }
        }
    }
}
